import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class Test implements ActionListener
{

    JTextPane pane;

    public Test()
    {
        JPanel p = new JPanel();
        JButton green = new JButton("green");
        green.addActionListener(this);
        p.add(green);
        JButton greenJagged = new JButton("greenJagged");
        greenJagged.addActionListener(this);
        p.add(greenJagged);
        JButton red = new JButton("red");
        red.addActionListener(this);
        p.add(red);
        JButton redJagged = new JButton("redJagged");
        redJagged.addActionListener(this);
        p.add(redJagged);
        JButton reset = new JButton("reset");
        reset.addActionListener(this);
        p.add(reset);

        JFrame fr = new JFrame("TEST");
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        pane = new JTextPane();
        pane.setEditorKit(new ExtendedEditorKit());
        String text = "test test test test\n";
        for (int i = 0; i < 20; i++)
        {
            text += "test test test test\n";
        }
        pane.setText(text);
        pane.setEditable(false);


        SimpleAttributeSet sty_keyword = new SimpleAttributeSet();
        StyleConstants.setForeground(sty_keyword, Color.blue);
        StyleConstants.setBold(sty_keyword, true);

        pane.getStyledDocument().setCharacterAttributes(0,20,sty_keyword, true);


        JScrollPane sp = new JScrollPane(pane);

        fr.getContentPane().add(sp);
        fr.getContentPane().add(p, BorderLayout.NORTH);
        fr.setSize(500, 500);
        fr.setVisible(true);
    }

    public static void main(String[] args)
    {
        new Test();
    }

    public void actionPerformed(ActionEvent e)
    {
        MutableAttributeSet as = new SimpleAttributeSet();
        if (e.getActionCommand().equals("green"))
        {
            setCustomUnderline(as, GREEN_UNDERLINE);
        }
        else
            if (e.getActionCommand().equals("red"))
            {
                setCustomUnderline(as, RED_UNDERLINE);
            }
            else
                if (e.getActionCommand().equals("redJagged"))
                {
                    setCustomUnderline(as, RED_JAGGED_UNDERLINE);
                }
                else
                    if (e.getActionCommand().equals("greenJagged"))
                    {
                        setCustomUnderline(as, GREEN_JAGGED_UNDERLINE);
                    }
                    else
                        if (e.getActionCommand().equals("reset"))
                        {
                            setCustomUnderline(as, NO_CUSTOM_UNDERLINE);
                        }
        pane.setCharacterAttributes(as, false);
    }

    public class ExtendedEditorKit extends StyledEditorKit
    {
        public ViewFactory getViewFactory()
        {
            return new ExtendedViewFactory();
        }

    }

    class ExtendedViewFactory implements ViewFactory
    {
        public View create(Element elem)
        {
            String kind = elem.getName();
            if (kind != null)
            {
                if (kind.equals(AbstractDocument.ContentElementName))
                {
                    return new ExtendedLabelView(elem);
                }
                else
                    if (kind.equals(AbstractDocument.ParagraphElementName))
                    {
                        return new ParagraphView(elem);
                    }
                    else
                        if (kind.equals(AbstractDocument.SectionElementName))
                        {
                            return new BoxView(elem, View.Y_AXIS);
                        }
                        else
                            if (kind.equals(StyleConstants.ComponentElementName))
                            {
                                return new ComponentView(elem);
                            }
                            else
                                if (kind.equals(StyleConstants.IconElementName))
                                {
                                    return new IconView(elem);
                                }
            }
            return new LabelView(elem);
        }
    }

    class ExtendedLabelView extends LabelView
    {

        public ExtendedLabelView(Element elem)
        {
            super(elem);
        }

        public void paint(Graphics g, Shape allocation)
        {
            super.paint(g, allocation);
            int customUnderlineType = getCustomUnderline(this.getElement()
                    .getAttributes());
            if (customUnderlineType == GREEN_JAGGED_UNDERLINE) paintJaggedLine(g, allocation, Color.green);
            else
                if (customUnderlineType == RED_JAGGED_UNDERLINE) paintJaggedLine(g, allocation, Color.red);
                else
                    if (customUnderlineType == GREEN_UNDERLINE) paintLine(g, allocation, Color.green);
                    else
                        if (customUnderlineType == RED_UNDERLINE) paintLine(g, allocation, Color.red);
        }

        public void paintJaggedLine(Graphics g, Shape a, Color color)
        {
            int y = (int) (a.getBounds().getY() + a.getBounds().getHeight());
            int x1 = (int) a.getBounds().getX();
            int x2 = (int) (a.getBounds().getX() + a.getBounds().getWidth());

            Color old = g.getColor();
            g.setColor(color);

            int w = 3;
            int h = 2;

            for (int i = x1; i <= x2; i += w * 2)
            {
                g.drawArc(i + 0, y - h, w, h, 0, 180);
                g.drawArc(i + w, y - h, w, h, 180, 181);
            }

            g.setColor(old);
        }

        public void paintLine(Graphics g, Shape a, Color color)
        {
            int y = (int) (a.getBounds().getY() + a.getBounds().getHeight());
            int x1 = (int) a.getBounds().getX();
            int x2 = (int) (a.getBounds().getX() + a.getBounds().getWidth());

            Color old = g.getColor();
            g.setColor(color);

            g.drawLine(x1, y - 2, x2, y - 2);
            g.setColor(old);
        }
    }

    public static final String CustomUnderline = "customUnderline";

    public static final int RED_UNDERLINE = 1;

    public static final int GREEN_UNDERLINE = 2;

    public static final int RED_JAGGED_UNDERLINE = 3;

    public static final int GREEN_JAGGED_UNDERLINE = 4;

    public static final int NO_CUSTOM_UNDERLINE = -1;

    public static void setCustomUnderline(MutableAttributeSet a, int type)
    {
        a.addAttribute(CustomUnderline, new Integer(type));
    }

    public static int getCustomUnderline(AttributeSet a)
    {
        Object o = a.getAttribute(CustomUnderline);
        if (o != null)
        {
            try
            {
                return Integer.parseInt(o.toString());
            }
            catch (Exception x)
            {
                return NO_CUSTOM_UNDERLINE;
            }
        }
        return NO_CUSTOM_UNDERLINE;
    }
}
